package zgame.config.loader;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import zgame.bean.Port;
import zgame.bean.Service;
import zgame.bean.Service.FUNCTION;
import zgame.bean.Service.TYPE;
import zgame.main.Global;

public class ServiceConfigReader {
  private static Logger log = Logger.getLogger(ServiceConfigReader.class);
  
  public static final String SERVICE_CONFIG_FILE = "conf/Service.xml";
  
  private Map<String, Service> servicesFromConfig = new HashMap<String, Service>();
  
  public void loadConfig() throws IOException {
    log.info("Read service info from config file: " + SERVICE_CONFIG_FILE);
    Document document = getDocument(SERVICE_CONFIG_FILE);
    Element services = document.getRootElement();

    Map<String, Service> servicesFromConfig = new HashMap<String, Service>();
    for (Iterator<Element> i = services.elementIterator(); i.hasNext();) {
      Element serviceNode = i.next();
      if (!serviceNode.getName().equals("service")) {
        throw new IOException("Config file " + SERVICE_CONFIG_FILE + " has wrong structure: The tag " + serviceNode.getName() + " can not be here");
      }

      String id = serviceNode.attributeValue("id");
      TYPE type = TYPE.valueOf(serviceNode.attributeValue("type").toUpperCase());
      String name = serviceNode.elementText("name");
      String description = serviceNode.elementText("description");
      FUNCTION function = FUNCTION.valueOf(serviceNode.elementText("function").toUpperCase());
      String validateKey = serviceNode.elementText("validateKey");

      String url = serviceNode.elementText("url");
      String maxUserTmp = serviceNode.elementText("maxUser");
      int maxUser = 0;
      if (maxUserTmp != null) {
        maxUser = Integer.parseInt(maxUserTmp);
      }

      Service service = new Service(id, name);
      service.setType(type);
      service.setDescription(description == null ? "" : description);
      service.setFunction(function);
      service.setValidateKey(validateKey);
      service.setUrl(url == null ? "" : url);
      service.setMaxUser(maxUser);

      // Get port list
      Element portsNode = serviceNode.element("ports");
      if (portsNode != null) {
        for (Iterator<Element> k = portsNode.elementIterator(); k.hasNext();) {
          Element portNode = k.next();
          String portName = portNode.elementText("name");
          int portValue = Integer.parseInt(portNode.elementText("value"));
          String portDescription = portNode.elementText("description");
          Port port = new Port();
          port.setName(portName);
          port.setValue(portValue);
          port.setDescription(portDescription == null ? "" : portDescription);
          service.addPort(port);
        }
      }

      switch (type) {
      case CURRENT:
        Global.currentServiceInfo = service;
        break;
      case OTHER:
        servicesFromConfig.put(service.getId(), service);
        break;
      }
      
      // Log service to console
      if (log.isDebugEnabled()) {
        log.debug(service);
      }
    }
    this.servicesFromConfig = servicesFromConfig; 
  }
  
  public Service getServiceFromConfig(String serviceId) {
    return servicesFromConfig.get(serviceId);
  }

  private Document getDocument(final String xmlFileName) {
    Document document = null;
    SAXReader reader = new SAXReader();
    try {
      document = reader.read(xmlFileName);
    } catch (DocumentException e) {
      log.error("Can not read config file: " + xmlFileName, e);
    }
    return document;
  }
}
